/***************************************************************
 * Name: cm.cpp 
 * Description: Constellation Mapping in System C
 * Author: Brian Peck
 * Date: Spring 2011
 ***************************************************************/

#include <systemc.h>

/**
 * cm - Constellation Mapping Module
 */
class cm : public sc_module
{
   public:
     // Use queues to receive input from stimulus and produce output
     sc_fifo_in<char> in;
     sc_fifo_out<float> out1;
     sc_fifo_out<float> out2;

     SC_HAS_PROCESS(cm);

     cm(sc_module_name name) : sc_module(name)
     {
       SC_THREAD(main);
     }

     void main()
     {
       char mask = 0x0F;
       char temp;
       char a;
       float x,y;
       // always be waiting for input
       while (1) {
         // when input arrives, perform constellation mapping
         in->read(a);
         temp = a & mask;
         switch(temp) {
           case 0:
             x = 1;  
             y = 1; 
             break; 
           case 1:
             x = 1;  
             y = 3; 
             break; 
           case 2:
             x = 3;  
             y = 1; 
             break; 
           case 3:
             x = 3;  
             y = 3; 
             break; 
           case 4:
             x = 1;  
             y = -1; 
             break; 
           case 5:
             x = 1;  
             y = -3; 
             break; 
           case 6:
             x = 3;  
             y = -1; 
             break; 
           case 7:
             x = 3;  
             y = -3; 
             break; 
           case 8:
             x = -1;  
             y = 1; 
             break; 
           case 9:
             x = -1;  
             y = 3; 
             break; 
           case 10:
             x = -3;  
             y = 1; 
             break; 
           case 11:
             x = -3;  
             y = 3; 
             break; 
           case 12:
             x = -1;  
             y = -1; 
             break; 
           case 13:
             x = -1;  
             y = -3; 
             break; 
           case 14:
             x = -3;  
             y = -1; 
             break; 
           case 15:
             x = -3;  
             y = -3; 
             break; 
	}  // end switch
        // output data to monitor
        out1->write(x);
        out2->write(y);
       }  //end while
     } // end main
}; //end class cm


/**
 * stimulus - produces input for the constellation mapping
 */
class stimulus : public sc_module
{
   public:
     // Use fifo queue to distribute input
     sc_fifo_out<char> out;
     SC_HAS_PROCESS(stimulus);

     stimulus(sc_module_name name) : sc_module(name)
     {
       SC_THREAD(main);
     }

     void main()
     {
       char c;
       cout << endl << endl;
       // loop through each of 16 possible input to demonstrate functionality
       for(c =0; c < 16; c++) {
         out->write(c);
       }
     }
};

/**
 * monitor - receives values from constellation mapping
 */
class monitor : public sc_module
{
   public:
     // Use 2 fifo queues to receive responses
     sc_fifo_in<float> in1;
     sc_fifo_in<float> in2;
     SC_HAS_PROCESS(monitor);

     monitor(sc_module_name name) : sc_module(name)
     {
       SC_THREAD(main);
     }

     void main()
     {
       char i;
       float c1, c2;
       // loop through and print each possible input to demonstrate cm
       for(i =0; i < 16; i++) {
         in1->read(c1);
         in2->read(c2);
         cout << c1 << "," << c2 << endl << flush;
       }
     }
};

/**
 * top - Links other modules together
 */
class top : public sc_module
{
   public:
     // Use fifo queues for communication
     sc_fifo<char> stim_cm;
     sc_fifo<float> cm_mon1;
     sc_fifo<float> cm_mon2;
     stimulus *stim_inst;
     cm * cm_inst;
     monitor *mon_inst;

     // Constructor, build 3 queues
     top(sc_module_name name) : sc_module(name), stim_cm("stim_cm", 10), cm_mon1("cm_mon1",10), cm_mon2("com_mon2",10)
     {
       // create modules and link queues
       stim_inst = new stimulus("Stimulus1");
       stim_inst->out(stim_cm);

       cm_inst = new cm("cm1");
       cm_inst->in(stim_cm);
       cm_inst->out1(cm_mon1);
       cm_inst->out2(cm_mon2);

       mon_inst = new monitor("Monitor1");
       mon_inst->in1(cm_mon1);
       mon_inst->in2(cm_mon2);
     }
};

/**
 * sc_main - Application Entry Point
 */
int sc_main (int argc , char *argv[]) {
   top top1("Top1");
   sc_start();
   return 0;
}

